#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/kdev_t.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include "beep.h"
 
static unsigned int major = 250;
static unsigned int minor = 0;
 
struct class *cls;
dev_t devno = 0;
#define KMAX_LEN 32
char kbuf[KMAX_LEN] = "kernel";

int
hello_open(struct inode *inode, struct file *file)
{
    printk("hello_open\n");
    return 0;
}

int
hello_release(struct inode *inode, struct file *file)
{
    printk("hello_release\n");
    return 0;
}
 
static int knum = 99;

long hello_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
{
    void __user *argp = (void __user *)arg;
    int __user *p = argp;
    int err;
    int ret;
    if(_IOC_TYPE(cmd)!=DEV_FIFO_TYPE)
    {
        pr_err("cmd   %u,bad magic 0x%x/0x%x.\n",cmd,_IOC_TYPE(cmd),DEV_FIFO_TYPE);
        return-ENOTTY;
     }
     if(_IOC_DIR(cmd)&_IOC_READ)
     {
         ret=!access_ok(VERIFY_WRITE,(void __user*)arg,_IOC_SIZE(cmd));//check addr
     }
     else if( _IOC_DIR(cmd)&_IOC_WRITE )
     {
         ret=!access_ok(VERIFY_READ,(void   __user*)arg,_IOC_SIZE(cmd));//check addr
     }
     if(ret)
     {
        pr_err("bad   access %ld.\n",ret);
        return-EFAULT;
     }
 
    switch(cmd)
    {
        case DEV_FIFO_CLEAN:
            printk("DEV_FIFO_CLEAN \n");
            break;
        case DEV_FIFO_GETVALUE:
            err = put_user(knum, p);
            printk("DEV_FIFO_GETVALUE\n" );
            break;
        case DEV_FIFO_SETVALUE:
            err = get_user(knum, p);
            printk("DEV_FIFO_SETVALUE knum=%d \n", knum);
            break;
        default:
            return -EINVAL;
    }
    return 0;
}

struct file_operations fops = 
{
    .open = hello_open,
    .release = hello_release,
    .unlocked_ioctl = hello_ioctl,
};

static int hello_init(void)
{
    int ret = 0;;
    struct device *class_dev;
    printk("hello_init\n");
    ret = register_chrdev(major, "zlyinit", &fops);
    if(ret < 0)
    {
        printk("register_chrdev fail\n");
        return ret;
    }
    cls = class_create(THIS_MODULE, "hellozlycls");// /sys/class/
    if (IS_ERR(cls)) {
        printk("class_create fail\n");
        ret = PTR_ERR(cls);
        goto out_err_1;
    }
    devno = MKDEV(major, minor);
    class_dev = device_create(cls, NULL, devno, "hellozlydev");// /dev/hellozlydev
    if (IS_ERR(class_dev)) {
        ret = PTR_ERR(class_dev);
        printk("device_create fail\n");
        goto out_err_2;
    }
    printk("device_create succ\n");
    return ret;
out_err_2:
    class_destroy(cls);
out_err_1:
    unregister_chrdev(major, "zlyinit");
    printk("ret=[%u]\n", ret);
    return ret;
}
 
static void hello_exit(void)
{
    printk("hello_exit\n");
    device_destroy(cls, devno);
    class_destroy(cls);
    unregister_chrdev(major, "zlyinit");
    return;
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");